﻿/*
    Copyright 2010, 2011 Eric Wong
	contact@optimalcycling.com
	http://www.optimalcycling.com
	Optimal Cycling - Advanced power pacing program for cyclists
	
	This file is part of Optimal Cycling.

    Optimal Cycling is free software: you can redistribute it and/or modify
    it under the terms of the GNU Lesser General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    Optimal Cycling is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU Lesser General Public License for more details.

    You should have received a copy of the GNU Lesser General Public License
    along with Optimal Cycling.  If not, see <http://www.gnu.org/licenses/>.
*/

using System;

namespace OptimalCycling
{
    #region Alias

    using sizeT = System.UInt32;
    using size_array = System.UInt32;

    // Allow us to easily switch between floats and double values
#if REAL_IS_DOUBLE
    using real = System.Double;
    using real2 = Vector2d;
    using real4 = Vector4d;
#else
    using real = System.Single;
    using real2 = Vector2;
    using real4 = Vector4;
#endif

    #endregion

    /// <summary>
    /// Common math operations for vectors.
    /// </summary>
    public static class VectorMath
    {
        /// <summary>
        /// Calculates the grade from a vector of X, Y, Z.
        /// </summary>
        /// <param name="a"> The vector of X, Y, Z. Note that the W component is ignored.</param>
        /// <returns>The grade in decimal form.</returns>
        public static real Grade(real4 a)
        {
            double run = Math.Sqrt(Math.Pow(a.X, 2) + Math.Pow(a.Z, 2));
            if (Math.Abs(run) < DataConstants.SMALL_REAL)
                throw new Exception("Run is too small at course point: " + a.X + "  " + a.Y + "  " + a.Z + "  .");
            return (real)(a.Y / run);
        }

        /// <summary>
        /// Calculates the unit vector from a vector of X, Y, Z, W.
        /// </summary>
        /// <param name="a"> The vector of X, Y, Z, W.</param>
        /// <returns>The unit vector as a real4 type.</returns>
        public static real4 Normalize(real4 a)
        {
            real4 unitVector;
            real vectLength = Length(a);

            if (vectLength < DataConstants.SMALL_REAL)
            {
                unitVector.X = 0;
                unitVector.Y = 0;
                unitVector.Z = 0;
                unitVector.W = 0;
            }
            else
            {
                unitVector.X = a.X / vectLength;
                unitVector.Y = a.Y / vectLength;
                unitVector.Z = a.Z / vectLength;
                unitVector.W = a.W / vectLength;
            }

            return unitVector;
        }

        /// <summary>
        /// Calculates the length of a vector from a vector of X, Y, Z, W.
        /// </summary>
        /// <param name="a"> The vector of X, Y, Z, W.</param>
        /// <returns>The length of the vector.</returns>
        public static real Length(real4 a)
        {
            return (real)Math.Sqrt(a.X * a.X + a.Y * a.Y + a.Z * a.Z + a.W * a.W);
        }
    }

    public static class DataConversion
    {
        public static real ConvertToReal(string data)
        {
#if REAL_IS_DOUBLE
            return Convert.ToDouble(data);
#else
            return Convert.ToSingle(data);
#endif
        }

        public static sizeT ConvertTosizeT(string data)
        {
            if (IntPtr.Size >= 8)   // 64-bit native
                return (sizeT)Convert.ToUInt64(data);
            else   // 32-bit native
                return (sizeT)Convert.ToUInt32(data);
        }
    }
}